/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bff.designtime.generator.core.rtgen.managergenerator.mgrImplclass.methodgenerators;

import com.inspur.edp.bef.component.detailcmpentity.vm.VMComponent;
import com.inspur.edp.bef.component.detailcmpentity.vm.VMMethod;
import com.inspur.edp.bff.api.attribute.VMDataExtendAttribute;
import com.inspur.edp.bff.api.attribute.VMRootAttribute;
import com.inspur.edp.bff.designtime.generator.core.rtgen.managergenerator.mgrImplclass.FSMgrImplGenContext;
import com.inspur.edp.bff.spi.IHelpMapping;
import com.inspur.edp.bff.spi.VMHelpConfig;
import com.inspur.edp.bff.spi.utils.ReflectInfo;
import com.inspur.edp.caf.generator.baseInfo.ParameterInfo;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.method.ClassMethodGenerator;
import com.inspur.edp.cef.gencommon.ReflectionUtils;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.action.MappedCdpAction;
import com.inspur.edp.formserver.viewmodel.action.ViewModelAction;
import com.inspur.edp.formserver.viewmodel.action.viewmodelbase.ViewModelParameter;
import com.inspur.edp.formserver.viewmodel.collection.ValueHelpConfigCollection;
import com.inspur.edp.formserver.viewmodel.common.ValueHelpConfig;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import org.eclipse.jdt.core.dom.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class GetHelpConfigMethodGenerator extends ClassMethodGenerator {

    private FSMgrImplGenContext fsMgrImplGenContext;
    private String param_labelId = "labelId";
    private String param_codeName = "codeName";

    public GetHelpConfigMethodGenerator(FSMgrImplGenContext fsMgrImplGenContext)
    {
        this.fsMgrImplGenContext = fsMgrImplGenContext;
    }

    @Override
    protected Block buildMethodBody() {
        Block block=ast.newBlock();

        HashMap<String,VMHelpConfig> map=getHelpConfig();

        SwitchStatement switchStatement=ast.newSwitchStatement();
        setSwitchExpression(switchStatement);
        if(map!=null)
            for(Map.Entry<String,VMHelpConfig> entry:map.entrySet())
            {
                addSwitchCaseExpression(switchStatement,entry);
            }
        addDefaultCaseExpression(switchStatement);

        block.statements().add(switchStatement);
        return block;
    }

    private void addDefaultCaseExpression(SwitchStatement switchStatement) {
        SwitchCase switchCase= ast.newSwitchCase();
        switchCase.setExpression(null);
        switchStatement.statements().add(switchCase);
        ReturnStatement returnStatement=ast.newReturnStatement();
        returnStatement.setExpression(ast.newNullLiteral());
        switchStatement.statements().add(returnStatement);
    }

    private void addSwitchCaseExpression(SwitchStatement switchStatement, Map.Entry<String, VMHelpConfig> entry) {
        addCaseExpression(switchStatement,entry);
        addCaseBody(switchStatement,entry);
    }

    private void addCaseExpression(SwitchStatement switchStatement, Map.Entry<String, VMHelpConfig> entry) {
        SwitchCase switchCase=ast.newSwitchCase();
        StringLiteral stringLiteral=ast.newStringLiteral();
        stringLiteral.setLiteralValue(entry.getKey());
        switchCase.setExpression(stringLiteral);
        switchStatement.statements().add(switchCase);
    }

    private void addCaseBody(SwitchStatement switchStatement, Map.Entry<String, VMHelpConfig> entry) {
        Block block=ast.newBlock();
        String key= entry.getKey();
        key  =key.replaceAll("-","");
        key=key.replaceAll("_","");
        String valName = "val"+key;

        String listValName = "val"+key +"List";
        addNewVMHelpConfig(block,entry,valName);
        addSetHelpId(block,entry, valName);
        addNewReflectInfos(block,entry,listValName);
        addSetReflectInfoItems(block,entry, listValName);
        addSetActionRecord(block,entry,valName, listValName);
        addSetUseCustomAuth(block,entry,valName,listValName);
        addSetVoID(block,entry,valName,listValName);
        addSetHelpElementID(block,entry,valName,listValName);
        addReturnConfig(block,valName);
        switchStatement.statements().add(block);
    }

    private void addReturnConfig(Block block, String valName) {
        ReturnStatement returnStatement=ast.newReturnStatement();

        returnStatement.setExpression(ast.newSimpleName(valName));
        block.statements().add(returnStatement);

    }

    private void addNewVMHelpConfig(Block block1, Map.Entry<String, VMHelpConfig> entry,String valName) {
        VariableDeclarationFragment variableDeclarationFragment=ast.newVariableDeclarationFragment();
        variableDeclarationFragment.setName(ast.newSimpleName(valName));
        ClassInstanceCreation classInstanceCreation=ast.newClassInstanceCreation();
        Type helpConfigType = new TypeInfo(VMHelpConfig.class).getType(ast, this.fsMgrImplGenContext.getMgrGenContext().getRootCompileUnitGenCtx());
        classInstanceCreation.setType(helpConfigType);
        variableDeclarationFragment.setInitializer(classInstanceCreation);

        VariableDeclarationStatement variableDeclarationStatement=ast.newVariableDeclarationStatement(variableDeclarationFragment);
        Type helpConfigType1 = new TypeInfo(VMHelpConfig.class).getType(ast, this.fsMgrImplGenContext.getMgrGenContext().getRootCompileUnitGenCtx());
        variableDeclarationStatement.setType(helpConfigType1);
        block1.statements().add(variableDeclarationStatement);
    }
    private void addSetHelpId(Block block1, Map.Entry<String, VMHelpConfig> entry,String valName)
    {
        MethodInvocation methodInvocation=ast.newMethodInvocation();
        methodInvocation.setExpression(ast.newSimpleName(valName));
        methodInvocation.setName(ast.newSimpleName("setHelpId"));
        StringLiteral stringLiteral=ast.newStringLiteral();
        stringLiteral.setLiteralValue(entry.getValue().getHelpId());
        methodInvocation.arguments().add(stringLiteral);

        block1.statements().add(ast.newExpressionStatement(methodInvocation));
    }
    private void addNewReflectInfos(Block block, Map.Entry<String, VMHelpConfig> entry,String listValName)
    {
        VariableDeclarationFragment variableDeclarationFragment=ast.newVariableDeclarationFragment();
        variableDeclarationFragment.setName(ast.newSimpleName(listValName));
        ClassInstanceCreation classInstanceCreation=ast.newClassInstanceCreation();

        Type listType = new TypeInfo(ArrayList.class).getType(ast,  this.fsMgrImplGenContext.getMgrGenContext().getRootCompileUnitGenCtx());
        Type reflectType = new TypeInfo(ReflectInfo.class).getType(ast,  this.fsMgrImplGenContext.getMgrGenContext().getRootCompileUnitGenCtx());
        ParameterizedType parameterizedType1=ast.newParameterizedType(listType);
        parameterizedType1.typeArguments().add(reflectType);
        classInstanceCreation.setType(parameterizedType1);
        variableDeclarationFragment.setInitializer(classInstanceCreation);

        Type listType2 = new TypeInfo(ArrayList.class).getType(ast,  this.fsMgrImplGenContext.getMgrGenContext().getRootCompileUnitGenCtx());
        Type reflectType2 = new TypeInfo(ReflectInfo.class).getType(ast,  this.fsMgrImplGenContext.getMgrGenContext().getRootCompileUnitGenCtx());
        VariableDeclarationStatement variableDeclarationStatement=ast.newVariableDeclarationStatement(variableDeclarationFragment);
        ParameterizedType parameterizedType=ast.newParameterizedType(listType2);
        parameterizedType.typeArguments().add(reflectType2);
        variableDeclarationStatement.setType(parameterizedType);
        block.statements().add(variableDeclarationStatement);
    }
    private void addSetReflectInfoItems(Block block, Map.Entry<String, VMHelpConfig> entry,String listValName)
    {
        if(entry.getValue().getActionRecord()==null||entry.getValue().getActionRecord().size()==0)
            return;
        int index = 1;
        for (ReflectInfo reflectInfo:entry.getValue().getActionRecord())
        {
            //含有参数
            String varListName = listValName + index++;
            if(reflectInfo.getParameterInfoList() != null && !reflectInfo.getParameterInfoList().isEmpty()){
                addImport(com.inspur.edp.bff.spi.utils.ParameterInfo.class.getName());
                addParameterInfo(block, reflectInfo, varListName);
            }
            MethodInvocation methodInvocation=ast.newMethodInvocation();
            methodInvocation.setName(ast.newSimpleName("add"));
            methodInvocation.setExpression(ast.newSimpleName(listValName));

            ClassInstanceCreation classInstanceCreation=ast.newClassInstanceCreation();
            classInstanceCreation.setType(new TypeInfo(ReflectInfo.class).getType(ast, this.fsMgrImplGenContext.getMgrGenContext().getRootCompileUnitGenCtx()));
            StringLiteral stringLiteral1=ast.newStringLiteral();
            stringLiteral1.setLiteralValue(reflectInfo.getAssemblyName());
            classInstanceCreation.arguments().add(stringLiteral1);
            StringLiteral stringLiteral2=ast.newStringLiteral();
            stringLiteral2.setLiteralValue(reflectInfo.getClassName());
            classInstanceCreation.arguments().add(stringLiteral2);
            if(reflectInfo.getParameterInfoList() != null && !reflectInfo.getParameterInfoList().isEmpty()){
                classInstanceCreation.arguments().add(ast.newSimpleName(varListName));
            }

            methodInvocation.arguments().add(classInstanceCreation);

            block.statements().add(ast.newExpressionStatement(methodInvocation));
        }
    }

    //生成添加参数代码
    private void addParameterInfo(Block block, ReflectInfo reflectInfo, String varListName)
    {
        VariableDeclarationFragment variableDeclarationFragment = ast.newVariableDeclarationFragment();
        ClassInstanceCreation classInstanceCreation = ast.newClassInstanceCreation();
        ParameterizedType parameterizedType = ast.newParameterizedType(ast.newSimpleType(ast.newSimpleName("ArrayList")));
        parameterizedType.typeArguments().add(ast.newSimpleType(ast.newSimpleName("ParameterInfo")));
        classInstanceCreation.setType(parameterizedType);

        variableDeclarationFragment.setName(ast.newSimpleName(varListName));
        variableDeclarationFragment.setInitializer(classInstanceCreation);

        VariableDeclarationStatement variableDeclarationStatement = ast.newVariableDeclarationStatement(variableDeclarationFragment);
        ParameterizedType parameterizedType1 = ast.newParameterizedType(ast.newSimpleType(ast.newSimpleName("ArrayList")));
        parameterizedType1.typeArguments().add(ast.newSimpleType(ast.newSimpleName("ParameterInfo")));
        variableDeclarationStatement.setType(parameterizedType1);

        block.statements().add(variableDeclarationStatement);
        for(com.inspur.edp.bff.spi.utils.ParameterInfo parameterInfo:reflectInfo.getParameterInfoList()){
            MethodInvocation methodInvocation = ast.newMethodInvocation();
            methodInvocation.setExpression(ast.newSimpleName(varListName));
            methodInvocation.setName(ast.newSimpleName("add"));
            ClassInstanceCreation classInstanceCreation1 = ast.newClassInstanceCreation();
            classInstanceCreation1.setType(ast.newSimpleType(ast.newSimpleName("ParameterInfo")));
            StringLiteral stringLiteral1=ast.newStringLiteral();
            stringLiteral1.setLiteralValue(parameterInfo.getParameterName());
            classInstanceCreation1.arguments().add(stringLiteral1);
            StringLiteral stringLiteral2=ast.newStringLiteral();
            stringLiteral2.setLiteralValue(parameterInfo.getParameterValue());
            classInstanceCreation1.arguments().add(stringLiteral2);
            methodInvocation.arguments().add(classInstanceCreation1);
            block.statements().add(ast.newExpressionStatement(methodInvocation));
        }
    }

    private void addSetActionRecord(Block block, Map.Entry<String, VMHelpConfig> entry, String valName, String valListName)
    {
        MethodInvocation methodInvocation=ast.newMethodInvocation();
        methodInvocation.setName(ast.newSimpleName("setActionRecord"));
        methodInvocation.setExpression(ast.newSimpleName(valName));
        methodInvocation.arguments().add(ast.newSimpleName(valListName));

        block.statements().add(ast.newExpressionStatement(methodInvocation));
    }

    private void addSetUseCustomAuth(Block block, Map.Entry<String, VMHelpConfig> entry, String valName, String listValName) {
        MethodInvocation methodInvocation=ast.newMethodInvocation();
        methodInvocation.setName(ast.newSimpleName("setUseCustomAuthInfo"));
        methodInvocation.setExpression(ast.newSimpleName(valName));
        methodInvocation.arguments().add(ast.newBooleanLiteral(entry.getValue().getUseCustomAuthInfo()));

        block.statements().add(ast.newExpressionStatement(methodInvocation));
    }

    private void addSetVoID(Block block, Map.Entry<String, VMHelpConfig> entry, String valName, String listValName) {
        MethodInvocation methodInvocation=ast.newMethodInvocation();
        methodInvocation.setName(ast.newSimpleName("setVoID"));
        methodInvocation.setExpression(ast.newSimpleName(valName));
        StringLiteral stringLiteral=ast.newStringLiteral();
        stringLiteral.setLiteralValue(entry.getValue().getVoID());
        methodInvocation.arguments().add(stringLiteral);

        block.statements().add(ast.newExpressionStatement(methodInvocation));
    }

    private void addSetHelpElementID(Block block, Map.Entry<String, VMHelpConfig> entry, String valName, String listValName) {
        MethodInvocation methodInvocation=ast.newMethodInvocation();
        methodInvocation.setName(ast.newSimpleName("setHelpElementID"));
        methodInvocation.setExpression(ast.newSimpleName(valName));
        StringLiteral stringLiteral=ast.newStringLiteral();
        stringLiteral.setLiteralValue(entry.getValue().getHelpElementID());
        methodInvocation.arguments().add(stringLiteral);

        block.statements().add(ast.newExpressionStatement(methodInvocation));
    }

    private void setSwitchExpression(SwitchStatement switchStatement) {
        InfixExpression infixExpression=ast.newInfixExpression();
        infixExpression.setLeftOperand(ast.newSimpleName(param_codeName));
        infixExpression.setOperator(InfixExpression.Operator.PLUS);
        infixExpression.setRightOperand(ast.newSimpleName(param_labelId));
        switchStatement.setExpression(infixExpression);
    }

    private HashMap<String, VMHelpConfig> getHelpConfig() {

        GspViewModel model = fsMgrImplGenContext.getMgrGenContext().getFSGeneratorContext().getVmGenContext().getVm();
        java.util.HashMap<String, VMHelpConfig> dic = new java.util.HashMap<String, VMHelpConfig>();

        ValueHelpConfigCollection helpInfos = model.getValueHelpConfigs();
        for (ValueHelpConfig config:helpInfos)
        {
            String originalKey = config.getElementId(); //此ID分两段，用/区分
            String[] info = originalKey.split("[/]", -1);
            if (info.length != 2) {
                throw new RuntimeException("ValueHelpConfig对象的ElementId字段不符合约定");
            }
            String key = info[0] + info[1];

            java.util.ArrayList<ReflectInfo> list = new java.util.ArrayList<ReflectInfo>();
            if (config.getHelpExtend() != null && config.getHelpExtend().getBeforeHelp() != null) {


                for (ViewModelAction helpAction : config.getHelpExtend().getBeforeHelp()) {
                    MappedCdpAction action = (MappedCdpAction) helpAction;
                    GspMetadata metadata = fsMgrImplGenContext.getMgrGenContext().getFSGeneratorContext().getVmGenContext().getMetadataPool()
                            .getMetadata(action.getComponentPkgName(), action.getComponentEntityId());

                    VMComponent compMetadata = (VMComponent) ((metadata.getContent() instanceof VMComponent)
                            ? metadata.getContent() : null);
                    if (compMetadata == null) {
                        throw new RuntimeException("加载构件失败");
                    }
                    List<com.inspur.edp.bff.spi.utils.ParameterInfo> parameters = new ArrayList<>();
                    for(int i=0;i<action.getParameterCollection().getCount();i++)
                    {
                        //todo 是不是有问题呢？
                        ViewModelParameter parameter = (ViewModelParameter)action.getParameterCollection().getItem(i);
                        String parameterValue =parameter.getActualValue().getValue() == null ? "" :parameter.getActualValue().getValue();
                        com.inspur.edp.bff.spi.utils.ParameterInfo parameterInfo = new com.inspur.edp.bff.spi.utils.ParameterInfo(parameter.getParamCode(), parameterValue);
                        parameters.add(parameterInfo);
                    }
                    VMMethod method = compMetadata.getVmMethod();
                    String assemblyName = method.getAssembly();
                    String className = method.getClassName();
                    list.add(new ReflectInfo(assemblyName, className, parameters));
                }
            }

            VMHelpConfig tempVar = new VMHelpConfig();
            tempVar.setHelpId(config.getHelperId());
            tempVar.setActionRecord(list);
            tempVar.setUseCustomAuthInfo(config.getEnableCustomHelpAuth());
            tempVar.setVoID(model.getID());
            tempVar.setHelpElementID(config.getElementId());
            dic.put(key, tempVar);
        }
        return dic;
    }

    @Override
    protected String getMethodName() {
        return "getHelpConfig";
    }

    @Override
    protected TypeInfo getReturnType() {
        return new TypeInfo(VMHelpConfig.class);
    }

    @Override
    protected ArrayList<Modifier.ModifierKeyword> getAccessModifiers() {
        ArrayList<Modifier.ModifierKeyword> list =new ArrayList<Modifier.ModifierKeyword>();
        list.add(Modifier.ModifierKeyword.PROTECTED_KEYWORD);
        return list;
    }

    @Override
    protected boolean getIsOverride() {
        return  true;
    }

    @Override
    protected ArrayList<ParameterInfo> getParameterCollection() {
        ArrayList<ParameterInfo> list =new ArrayList<ParameterInfo>();
        ParameterInfo info  =new ParameterInfo();
        info.setParamType(new TypeInfo(String.class));
        info.setParamName(param_codeName);
        list.add(info);
        info  =new ParameterInfo();
        info.setParamType(new TypeInfo(String.class));
        info.setParamName(param_labelId);
        list.add(info);

        return list;
    }
}
